package com.bort.system.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bort.system.common.DataContainer;
import com.bort.system.controller.client.CloseDialogController;
import com.bort.system.info.Business;
import com.bort.system.info.CheckOutResult;
import com.bort.system.mapper.TDeskMapper;
import com.bort.system.mapper.TGameLogMapper;
import com.bort.system.model.TDesk;
import com.bort.system.model.TGameLog;
import com.bort.system.service.TDeskService;
import com.bort.system.info.DeskInfo;
import com.bort.system.utils.Result;
import javafx.scene.control.ComboBox;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.One;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import sun.security.krb5.internal.crypto.Des;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TDeskServiceImpl extends ServiceImpl<TDeskMapper, TDesk> implements TDeskService {

    @Resource
    TDeskMapper deskMapper;

    @Resource
    TGameLogMapper gameLogMapper;

    @Override
    public List<DeskInfo> getAllDesk() {
        Map<String,Object> map = new HashMap<>();
        List<DeskInfo> list = deskMapper.getDeskInfoList(map);
        refreshData(list);
        return list;
    }

    @Override
    public List<DeskInfo> getDeskList(Page<DeskInfo> page, Map<String,Object> map) {
        List<DeskInfo> list = deskMapper.getDeskInfoList(page,map);
        page.setRecords(list);
        return list;
    }

    @Override
    public TGameLog openDesk(DeskInfo data, Integer hour, Integer minute, String player) {
        TGameLog gameLog = addGameLog(data, hour, minute, player,new Date(),null);
        return gameLog;
    }

    private TGameLog addGameLog(DeskInfo data, Integer hour, Integer minute, String player,Date now,Integer parentId){
        Integer limited = 1;
        data.setStatus("2");
        deskMapper.updateByPrimaryKeySelective(data);
        gameLogMapper.renewLastTag(data.getId());
        TGameLog gameLog = new TGameLog();
        gameLog.setDeskId(data.getId());
        gameLog.setCreateTime(now);
        gameLog.setStatus("2");
        gameLog.setLastTag(1);
        gameLog.setParentId(parentId);
        gameLog.setCreateUserId(DataContainer.loginUser.getId());
        gameLog.setPlayer(player);
        gameLog.setPrice(data.getPrice());
        gameLog.setTimeLimit(data.getTimeLimit());
        if(limited.equals(data.getTimeLimit())){
            gameLog.setTotalTime(minute + hour*60);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(now);
            calendar.add(Calendar.HOUR,hour);
            calendar.add(Calendar.MINUTE,minute);
            Date endTime = calendar.getTime();
            gameLog.setEndTime(endTime);
            int totalMinutes = hour * 60 + minute;

            BigDecimal perMinute = data.getPrice().divide(new BigDecimal(60),2,BigDecimal.ROUND_HALF_UP);
            BigDecimal amount = perMinute.multiply(new BigDecimal(totalMinutes));
            gameLog.setAmount(amount);
        }

        gameLogMapper.insert(gameLog);
        return gameLog;
    }

    @Override
    public boolean closeDesk(DeskInfo data,Date endTime,BigDecimal pay) {
        TDesk entity = deskMapper.selectById(data.getId());
        TGameLog gameLog = gameLogMapper.selectById(data.getLogId());

        CheckOutResult result = checkOut(gameLog.getCreateTime(), endTime, entity.getPrice());

        BigDecimal goMinute = result.getHour().multiply(new BigDecimal(60)).add(result.getMinute());
        gameLog.setTotalTime(goMinute.intValue());
        BigDecimal goHour = result.getHour().add(result.getMinute().divide(new BigDecimal(60),2,BigDecimal.ROUND_DOWN));

        entity.setStatus("1");
        entity.setUpdateTime(endTime);
        BigDecimal totalTime = entity.getTotalTime() != null?entity.getTotalTime():new BigDecimal(0);
        entity.setTotalTime(totalTime.add(goHour));

        BigDecimal totalIncome = entity.getTotalIncome() != null?entity.getTotalIncome():new BigDecimal(0);
        entity.setTotalIncome(totalIncome.add(pay));
        updateById(entity);
        gameLog.setEndTime(endTime);
        gameLog.setIncome(pay);
        gameLog.setAmount(pay);
        gameLog.setStatus("3");
        gameLogMapper.updateByPrimaryKeySelective(gameLog);
        return true;
    }

    @Override
    public void refreshData() {
        List<DeskInfo> list = getAllDesk();
        refreshData(list);
    }

    @Override
    public void refreshData(List<DeskInfo> deskInfos) {
        Date now = new Date();
        for (DeskInfo deskInfo : deskInfos) {
            Integer limit = deskInfo.getTimeLimit();
            String status = deskInfo.getStatus();
            if(limit != null && limit.equals(1)){
                if("2".equals(status)){
                    if(!now.before(deskInfo.getEndTime())){
                        TDesk desk = getDeskById(deskInfo.getId());
                        TGameLog game = new TGameLog();
                        game.setId(deskInfo.getLogId());
                        game.setStatus("3");
                        game.setDeskId(deskInfo.getId());
                        CheckOutResult result = checkOut(deskInfo.getStartTime(), deskInfo.getEndTime(), deskInfo.getPrice());
                        game.setIncome(result.getTotalMoney());
                        BigDecimal totalTime = result.getHour().multiply(new BigDecimal(60)).add(result.getMinute());
                        game.setTotalTime(totalTime.intValue());
                        gameLogMapper.updateByPrimaryKeySelective(game);
                        desk.setId(deskInfo.getId());
                        desk.setUpdateTime(now);
                        desk.setStatus("1");
                        BigDecimal mHours = result.getMinute().divide(new BigDecimal(60),2,BigDecimal.ROUND_DOWN);
                        BigDecimal hTotalTime = result.getHour().add(mHours);
                        desk.setTotalTime(desk.getTotalTime().add(hTotalTime));
                        BigDecimal totalIncome = desk.getTotalIncome() != null?desk.getTotalIncome():new BigDecimal(0);
                        desk.setTotalIncome(totalIncome.add(game.getIncome()));
                        updateById(desk);
                    }
                }
            }
        }
    }

    @Override
    public DeskInfo getDeskById(Integer id) {
        return deskMapper.getDeskInfoById(id);
    }

    @Override
    public int addDesk(TDesk desk) {
        desk.setCreateTime(new Date());
        desk.setStatus("1");
        boolean res = save(desk);
        return res?1:0;
    }

    @Override
    public int updateDesk(TDesk desk) {
       desk.setUpdateTime(new Date());
       desk.setUpdateUserId(DataContainer.loginUser.getId());
       updateById(desk);
       return 1;
    }

    @Override
    public int deleteDesk(Integer deskId) {
        removeById(deskId);
        return 0;
    }

    @Override
    public Page<TGameLog> getGameLogList(int page, int rowSize,Map<String,Object> map) {
       Page<TGameLog> pager = new Page<>();
       pager.setSize(rowSize);
       pager.setCurrent(page);
       List<TGameLog> list = gameLogMapper.getLogList(map,pager);
       pager.setRecords(list);
       return pager;
    }

    @Override
    public Result<Map<String, Object>> getDataCount(Map<String, Object> map) {
        Map<String,Object> result = gameLogMapper.dataCount(map);
        return Result.success(result);
    }

    @Override
    public Result countTopData(Map<String, Object> params) {
        if(params.get("timeRange") != null){
            List<String> ranges = JSONArray.parseArray(JSONObject.toJSONString(params.get("timeRange")), String.class);
            if(ranges.size() == 2){
                params.put("timeStart",ranges.get(0));
                params.put("timeEnd",ranges.get(1));
            }
        }
        List<Business> list = gameLogMapper.countHomeTopData(params);
        List<String> deskNames = list.stream().map(Business::getDeskName).collect(Collectors.toList());
        List<BigDecimal> timeList = list.stream().map(mp ->
                mp.getTotalTime() != null? mp.getTotalTime().divide(new BigDecimal(60),2,BigDecimal.ROUND_HALF_UP):new BigDecimal(0)
        ).collect(Collectors.toList());
        List<BigDecimal> incomeList = list.stream().map(Business::getTotalMoney).collect(Collectors.toList());

        Map<String,Object> data = new HashMap<>();

        BigDecimal totalMoney = new BigDecimal(0);
        BigDecimal totalTime = new BigDecimal(0);
        for (Business business : list) {
            totalMoney = totalMoney.add(null != business.getTotalMoney()?business.getTotalMoney():BigDecimal.ZERO);
            totalTime = totalTime.add(null != business.getTotalTime()?business.getTotalTime().divide(new BigDecimal(60),BigDecimal.ROUND_HALF_UP):new BigDecimal(0));
        }

        timeList.add(totalTime);
        incomeList.add(totalMoney);
        deskNames.add("合计");
        data.put("deskNames",deskNames);
        data.put("timeList",timeList);
        data.put("totalIncome",incomeList);

        List<Map<String,Object>> circle = new ArrayList<>();
        for (Business business : list) {
            Map<String,Object> map = new HashMap<>();
            map.put("name",business.getDeskName());
            map.put("value",business.getTotalMoney());
            circle.add(map);
        }
        data.put("circle",circle);

        return Result.success(data);
    }

    @Override
    public Result countLineData(Map<String, Object> params) {
        return null;
    }

    @Override
    public TGameLog addOvertime(DeskInfo data, Integer value, Integer minute) {
        TGameLog parent = gameLogMapper.selectById(data.getLogId());
        TGameLog log = addGameLog(data, value, minute, data.getPlayer(),parent.getEndTime(), data.getLogId());
        int totalTime = parent.getTotalTime() + log.getTotalTime();
        BigDecimal amount = parent.getAmount().add(log.getAmount());
        Date end = log.getEndTime();
        parent.setTotalTime(totalTime);
        parent.setAmount(amount);
        parent.setEndTime(end);
        gameLogMapper.updateById(parent);
        return parent;
    }

    public CheckOutResult checkOut(Date startTime, Date endTime, BigDecimal price) {
        long startSecond = startTime.getTime()/1000;
        long endSecond = endTime.getTime()/1000;
        long timeLong = endSecond - startSecond;
        BigDecimal hours = new BigDecimal(timeLong).divide(new BigDecimal(3600),0,BigDecimal.ROUND_DOWN);
        BigDecimal minutes = (new BigDecimal(timeLong/60)).subtract(hours.multiply(new BigDecimal(60)));
        BigDecimal hoursAmount = hours.multiply(price);
        BigDecimal minutesAmount = minutes.multiply(price).divide(new BigDecimal(60),2,BigDecimal.ROUND_DOWN);
        BigDecimal total = hoursAmount.add(minutesAmount).setScale(0,BigDecimal.ROUND_HALF_UP);
        return new CheckOutResult(total,hours,minutes);
    }

}
